//功能：负责编译模板，解析指令和表达式、负责页面首次渲染、当数据变化时重新渲染视图

class Compiler {
    constructor(vm){
        this.$el = vm.$el //vm：vue实例
        this.vm = vm 
        this.compiler(this.$el)
    }
    //编译模板；处理文本节点和元素节点
    compiler (el) {
        let childNodes = el.childNodes //el是div#app;childNodes是伪数组，用Array.
        console.log("childNodes::",childNodes)
        Array.from(childNodes).forEach(node => {
            if( this.isTextNode(node) ) {
                this.compilerText(node)
            }else if( this.isElementNode(node) ) {
                this.compilerElement(node)
            }
            //判断node是否有子节点，如果有子节点则递归调用compiler
            if(node.childNodes && node.childNodes.length) {
                this.compiler(node)
            }
        })
    }
    //编译元素节点，处理指令
    compilerElement (node) {
        // console.log(node.attributes) //节点的属性；
        //遍历所有属性节点，判断是否是指令v-if 等等；
        Array.from(node.attributes).forEach(attr => {
            let attrName = attr.name
            // console.log('keyyyyy::',attr,attr.name,attr.value)
            
            if( this.isDirective(attrName) ) {
                //v-text =>text v-model =>model
                attrName = attrName.substr(2)
                let key = attr.value
                this.update(node,key,attrName)
            }
        })
    }
    update (node,key,attrName) {
        let updateFn = this[attrName + 'Updater']
        updateFn && updateFn.call(this,node,this.vm[key],key) //指向Compiler类 相当于this.textUpdater(xxx,xxx,xxx)
    }
    //处理v-text 指令
    textUpdater (node,value,key) {
        node.textContent = value //改变textContent就会改变视图的值

        //创建watcher对象，当数据改变更新视图
        new Watcher(this.vm,key,(newValue)=>{
            console.log('watch::',newValue)
            node.textContent = newValue
        })
    }
    //处理v-model 指令
    modelUpdater (node,value,key) {
        node.value = value
        //创建watcher对象，当数据改变更新视图
        new Watcher(this.vm,key,(newValue)=>{
            node.value = newValue
        })
        //双向绑定
        node.addEventListener('input',()=> {
            this.vm[key] = node.value
        })
    }    
    //编译文本节点，处理差值表达式
    compilerText (node) {
        // console.log(node)
        // {{ msg }}  正则匹配 差值表达式
        let reg = /\{\{(.+?)\}\}/
        let value = node.textContent
        if(reg.test(value)) {
            let key = RegExp.$1.trim()
            node.textContent = value.replace(reg,this.vm[key])

            //创建watcher对象，当数据改变更新视图
            new Watcher(this.vm,key,(newValue)=>{
                console.log('watch::',newValue)
                node.textContent = newValue
            })

        }
    }
    //判断元素属性是否是指令
    isDirective (attrName) {
        return attrName.startsWith('v-')
    }
    //判读是否是文本节点
    isTextNode (node) {
        return node.nodeType === 3
    }
    //判断是否是元素节点
    isElementNode (node) {
        return node.nodeType === 1
    }
}


